using System;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections;
using EnvDTE;
using Extensibility;
using VSLangProj;
using VSLangProj80;
using VsWebSite;
using System.Diagnostics;
using Microsoft.VisualStudio.CommandBars;
using System.Text;
using Microsoft.Win32;
using Thinktecture.Tools.Web.Services.Wscf.Environment;
using PrjKind = VSLangProj.PrjKind;

using Thinktecture.Tools.Web.Services.CodeGeneration;
using Thinktecture.Tools.Web.Services.WsdlWizard;

namespace Thinktecture.Tools.Web.Services.ContractFirst
{
    using DteConstants = Constants;
    using EnvDTE80;

    #region Read me for Add-in installation and setup information.
    // When run, the Add-in wizard prepared the registry for the Add-in.
    // At a later time, if the Add-in becomes unavailable for reasons such as:
    //   1) You moved this project to a computer other than which is was originally created on.
    //   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
    //   3) Registry corruption.
    // you will need to re-register the Add-in by building the WsContractFirstSetup project 
    // by right clicking the project in the Solution Explorer, then choosing install.
    #endregion

    /// <summary>
    ///   The object for implementing an Add-in.
    /// </summary>
    /// <seealso class='IDTExtensibility2' />
    //[ComVisible(true)]
    //[StructLayout(LayoutKind.Sequential)]
    //
    // NOTE: Enable comments starting with *** to enable the simple logging mechanism we use.
    //
    [Guid("6C6DA7B1-0758-41f4-9669-04ED4B037669"), ProgId("Thinktecture.Tools.Web.Services.ContractFirst.Connect")]
    public class Connect : Object, IDTExtensibility2, IDTCommandTarget
    {
        // BDS: Save the last file name and the file counter in a hash table.
        private Hashtable fileCounters = null;
        private bool addDuplictedTypesAlert = false;
        private bool overwriteFiles = false;
        private DTE2 applicationObject;
        private AddIn addInInstance;

        /// <summary>
        ///		Implements the constructor for the Add-in object.
        ///		Place your initialization code within this method.
        /// </summary>
        public Connect()
        {
            if (fileCounters == null)
            {
                fileCounters = new Hashtable();
            }
            AppLog.LogMessage("A new instance of WSCF Connect class is created.");
        }

        /// <summary>
        ///      Implements the OnConnection method of the IDTExtensibility2 interface.
        ///      Receives notification that the Add-in is being loaded.
        /// </summary>
        /// <param term='application'>
        ///      Root object of the host application.
        /// </param>
        /// <param term='connectMode'>
        ///      Describes how the Add-in is being loaded.
        /// </param>
        /// <param term='addInInst'>
        ///      Object representing this Add-in.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            AppLog.LogMessage("Entering OnConnection method.");

            this.applicationObject = (DTE2)application;
            this.addInInstance = (AddIn)addInInst;
            object[] contextGUIDS = new object[] { };
            CommandBar cmdBar;
            Command cmdObj;

            if (connectMode == ext_ConnectMode.ext_cm_Startup ||
                connectMode == ext_ConnectMode.ext_cm_AfterStartup ||
                connectMode == ext_ConnectMode.ext_cm_UISetup)
            {
                AppLog.LogMessage("Creating commands.");

                Commands2 commands = (Commands2)applicationObject.Commands;
                CommandBars commandBars = (CommandBars)applicationObject.CommandBars;

                try
                {
                    Command command = commands.AddNamedCommand2(
                        addInInstance,
                        "WsContractFirst",
                        "Web Services Contract-First...",
                        "Executes the command for WsContractFirstAddin",
                        true,
                        190,
                        ref contextGUIDS,
                        (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled,
                        (int)vsCommandStyle.vsCommandStylePictAndText,
                        vsCommandControlType.vsCommandControlTypeButton);

                    CommandBar commandBar = commandBars["Tools"];
                    command.AddControl(commandBar, 1);

                    AppLog.LogMessage("Command bar is added to the Tools menu.");
                }
                catch (ArgumentException)
                {
                }
                catch (Exception e)
                {
                    AppLog.LogMessage(e.Message);
                }

                // Create the 'Generate Web Service Code...' context-menu entry
                try
                {
                    // Create the add-in command
                    cmdObj = commands.AddNamedCommand2(
                        addInInstance,
                        "WsContractFirstContextMenu",
                        "Generate Web Service Code...",
                        "Executes the command for WsContractFirstAddin ContextMenu",
                        true,
                        190,
                        ref contextGUIDS,
                        (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled,
                        (int)vsCommandStyle.vsCommandStylePictAndText,
                        vsCommandControlType.vsCommandControlTypeButton);

                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Item"];
                    cmdObj.AddControl(cmdBar, 1);

                    // BDS 11/21/2005: Add this menu item to the web project 
                    // template.
                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Web Item"];
                    cmdObj.AddControl(cmdBar, 1);

                    AppLog.LogMessage("Generate Web Serive Code menu item is added.");
                }
                catch (ArgumentException e)
                {
                    AppLog.LogMessage(e.Message);
                }
                catch (Exception ex)
                {
                    AppLog.LogMessage(ex.Message);
                }

                // Create the 'Edit WSDL Interface Description...' context-menu entry
                try
                {
                    // Create the add-in command
                    cmdObj = commands.AddNamedCommand2(
                        addInInstance,
                        "EditWsdlContextMenu",
                        "Edit WSDL Interface Description...",
                        "Executes the command for WsContractFirstAddin ContextMenu",
                        true,
                        190,
                        ref contextGUIDS,
                        (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled,
                        (int)vsCommandStyle.vsCommandStylePictAndText,
                        vsCommandControlType.vsCommandControlTypeButton);

                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Item"];
                    cmdObj.AddControl(cmdBar, 2);

                    // BDS 11/21/2005: Add this menu item to the web project 
                    // template.
                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Web Item"];
                    cmdObj.AddControl(cmdBar, 2);

                    AppLog.LogMessage("Edit WSDL menu item is added");
                }
                catch (ArgumentException e)
                {
                    AppLog.LogMessage(e.Message);
                }
                catch (Exception ex)
                {
                    AppLog.LogMessage(ex.Message);
                }

                // Create the 'Create WSDL Interface Description...' context-menu entry
                try
                {
                    // Create the add-in command
                    cmdObj = commands.AddNamedCommand2(
                        addInInstance,
                        "CreateWsdlContextMenu",
                        "Create WSDL Interface Description...",
                        "Executes the command for WsContractFirstAddin ContextMenu",
                        true,
                        190,
                        ref contextGUIDS,
                        (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled,
                        (int)vsCommandStyle.vsCommandStylePictAndText,
                        vsCommandControlType.vsCommandControlTypeButton);

                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Item"];
                    cmdObj.AddControl(cmdBar, 1);

                    // BDS 11/21/2005: Add this menu item to the web project 
                    // template.
                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Web Item"];
                    cmdObj.AddControl(cmdBar, 1);

                    AppLog.LogMessage("Create WSDL interface desc menu item is added");
                }
                catch (ArgumentException e)
                {
                    AppLog.LogMessage(e.Message);
                }
                catch (Exception ex)
                {
                    AppLog.LogMessage(ex.Message);
                }


                // Create the 'Choose WSDL to implement...' context-menu entry
                try
                {
                    // Create the add-in command
                    cmdObj = commands.AddNamedCommand2(
                        addInInstance,
                        "WsContractFirstContextMenu2",
                        "Choose WSDL to Implement...",
                        "Executes the command for WsContractFirstAddin ContextMenu",
                        true,
                        190,
                        ref contextGUIDS,
                        (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled,
                        (int)vsCommandStyle.vsCommandStylePictAndText,
                        vsCommandControlType.vsCommandControlTypeButton);

                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Project"];
                    cmdObj.AddControl(cmdBar, 3);

                    // BDS 11/21/2005: Add this menu item to the web project 
                    // template. 
                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Web Project Folder"];
                    cmdObj.AddControl(cmdBar, 3);

                    AppLog.LogMessage("Choose WSDL menu item is added");
                }
                catch (ArgumentException e)
                {
                    AppLog.LogMessage(e.Message);
                }
                catch (Exception ex)
                {
                    AppLog.LogMessage(ex.Message);
                }

                // Create the 'Generate code...' context-menu entry
                try
                {
                    // Create the add-in command
                    cmdObj = commands.AddNamedCommand2(
                        addInInstance,
                        "GenerateCodeMenu",
                        "Generate Data Contract Code...",
                        "Executes the command for WsContractFirstAddin ContextMenu",
                        true,
                        190,
                        ref contextGUIDS,
                        (int)vsCommandStatus.vsCommandStatusUnsupported + (int)vsCommandStatus.vsCommandStatusEnabled,
                        (int)vsCommandStyle.vsCommandStylePictAndText,
                        vsCommandControlType.vsCommandControlTypeButton);

                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Item"];
                    cmdObj.AddControl(cmdBar, 2);

                    // BDS 11/21/2005: Add this menu item to the web project 
                    // template. 
                    cmdBar = ((CommandBars)applicationObject.CommandBars)["Web Item"];
                    cmdObj.AddControl(cmdBar, 2);

                    AppLog.LogMessage("Generate code menu item is added");
                }
                catch (ArgumentException e)
                {
                    AppLog.LogMessage(e.Message);
                }
                catch (Exception ex)
                {
                    AppLog.LogMessage(ex.Message);
                }
            }

            AppLog.LogMessage("Leaving OnConnection method.");
        }

        /// <summary>
        ///     Implements the OnDisconnection method of the IDTExtensibility2 interface.
        ///     Receives notification that the Add-in is being unloaded.
        /// </summary>
        /// <param term='disconnectMode'>
        ///      Describes how the Add-in is being unloaded.
        /// </param>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
        {
            AppLog.LogMessage("Entering OnDisconnection method.");

            try
            {
                if (disconnectMode == Extensibility.ext_DisconnectMode.ext_dm_HostShutdown |
                    disconnectMode == Extensibility.ext_DisconnectMode.ext_dm_UserClosed)
                {
                    RemoveCommand("Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirst");
                    RemoveCommand("Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirstContextMenu");
                    RemoveCommand("Thinktecture.Tools.Web.Services.ContractFirst.Connect.EditWsdlContextMenu");
                    RemoveCommand("Thinktecture.Tools.Web.Services.ContractFirst.Connect.CreateWsdlContextMenu");
                    RemoveCommand("Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirstContextMenu2");
                    RemoveCommand("Thinktecture.Tools.Web.Services.ContractFirst.Connect.GenerateCodeMenu");
                }

            }
            catch (Exception ex)
            {
                AppLog.LogMessage(ex.Message);
                throw;
            }

            AppLog.LogMessage("Leaving OnDisconnection method.");
        }

        public void RemoveCommand(string Command)
        {
            Command cmd = null;
            try
            {
                cmd = applicationObject.Commands.Item(Command, -1);
            }
            catch
            {
            }

            if (cmd != null)
            {
                cmd.Delete();
            }
        }

        /// <summary>
        ///      Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
        ///      Receives notification that the collection of Add-ins has changed.
        /// </summary>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnAddInsUpdate(ref Array custom)
        {
        }

        /// <summary>
        ///      Implements the OnStartupComplete method of the IDTExtensibility2 interface.
        ///      Receives notification that the host application has completed loading.
        /// </summary>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnStartupComplete(ref Array custom)
        {
        }

        /// <summary>
        ///      Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
        ///      Receives notification that the host application is being unloaded.
        /// </summary>
        /// <param term='custom'>
        ///      Array of parameters that are host application specific.
        /// </param>
        /// <seealso class='IDTExtensibility2' />
        public void OnBeginShutdown(ref Array custom)
        {
        }

        /// <summary>
        ///      Implements the QueryStatus method of the IDTCommandTarget interface.
        ///      This is called when the command's availability is updated
        /// </summary>
        /// <param term='commandName'>
        ///		The name of the command to determine state for.
        /// </param>
        /// <param term='neededText'>
        ///		Text that is needed for the command.
        /// </param>
        /// <param term='status'>
        ///		The state of the command in the user interface.
        /// </param>
        /// <param term='commandText'>
        ///		Text requested by the neededText parameter.
        /// </param>
        /// <seealso class='Exec' />
        public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
        {
            AppLog.LogMessage("Entering QueryStatus method.");

            try
            {
                status = vsCommandStatus.vsCommandStatusInvisible;
                if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.EditWsdlContextMenu")
                {
                    UIHierarchy uiHierarchy = (UIHierarchy)applicationObject.Windows.Item(
                        DteConstants.vsWindowKindSolutionExplorer).Object;
                    foreach (UIHierarchyItem item in (Array)uiHierarchy.SelectedItems)
                    {
                        string itemName = item.Name;

                        if (itemName.IndexOf(".wsdl") > -1)
                        {
                            status = (vsCommandStatus)vsCommandStatus.vsCommandStatusEnabled |
                                vsCommandStatus.vsCommandStatusSupported;
                            AppLog.LogMessage("Edit WSDL command is enabled.");
                            break;
                        }
                    }
                }

                if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirstContextMenu")
                {
                    UIHierarchy uiHierarchy = (UIHierarchy)applicationObject.Windows.Item(
                        DteConstants.vsWindowKindSolutionExplorer).Object;
                    foreach (UIHierarchyItem item in (Array)uiHierarchy.SelectedItems)
                    {
                        string itemName = item.Name;

                        if (itemName.IndexOf(".wsdl") > -1)
                        {
                            status = (vsCommandStatus)vsCommandStatus.vsCommandStatusEnabled |
                                vsCommandStatus.vsCommandStatusSupported;
                            AppLog.LogMessage("WSCF context menu is enabled.");
                            break;
                        }
                    }
                }

                if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.CreateWsdlContextMenu")
                {
                    UIHierarchy uiHierarchy = (UIHierarchy)applicationObject.Windows.Item(
                        DteConstants.vsWindowKindSolutionExplorer).Object;
                    foreach (UIHierarchyItem item in (Array)uiHierarchy.SelectedItems)
                    {
                        string itemName = item.Name;

                        if (itemName.IndexOf(".xsd") > -1)
                        {
                            status = (vsCommandStatus)vsCommandStatus.vsCommandStatusEnabled |
                                vsCommandStatus.vsCommandStatusSupported;
                            AppLog.LogMessage("Create WSDL command is enabled");
                            break;
                        }
                    }
                }

                if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.GenerateCodeMenu")
                {
                    UIHierarchy uiHierarchy = (UIHierarchy)applicationObject.Windows.Item(
                        DteConstants.vsWindowKindSolutionExplorer).Object;
                    foreach (UIHierarchyItem item in (Array)uiHierarchy.SelectedItems)
                    {
                        string itemName = item.Name;

                        if (itemName.IndexOf(".xsd") > -1 || itemName.IndexOf(".wsdl") > -1)
                        {
                            status = (vsCommandStatus)vsCommandStatus.vsCommandStatusEnabled |
                                vsCommandStatus.vsCommandStatusSupported;
                            AppLog.LogMessage("Generate code command is enabled");
                            break;
                        }
                    }
                }

                if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
                {
                    if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirstContextMenu2")
                    {
                        status = (vsCommandStatus)vsCommandStatus.vsCommandStatusEnabled |
                            vsCommandStatus.vsCommandStatusSupported;
                        AppLog.LogMessage("WSCF menu 2 command is enabled");
                    }
                    if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirst")
                    {
                        status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported |
                            vsCommandStatus.vsCommandStatusEnabled;
                        AppLog.LogMessage("Contract first command is enabled");
                    }
                }
            }
            catch (Exception ex)
            {
                AppLog.LogMessage(ex.Message);
                throw;
            }

            AppLog.LogMessage("Leaving QueryStatus method.");
        }

        /// <summary>
        ///      Implements the Exec method of the IDTCommandTarget interface.
        ///      This is called when the command is invoked.
        /// </summary>
        /// <param term='commandName'>
        ///		The name of the command to execute.
        /// </param>
        /// <param term='executeOption'>
        ///		Describes how the command should be run.
        /// </param>
        /// <param term='varIn'>
        ///		Parameters passed from the caller to the command handler.
        /// </param>
        /// <param term='varOut'>
        ///		Parameters passed from the command handler to the caller.
        /// </param>
        /// <param term='handled'>
        ///		Informs the caller if the command was handled or not.
        /// </param>
        /// <seealso class='Exec' />
        public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
        {
            AppLog.LogMessage("Entering Exec method.");

            handled = false;

            if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirstContextMenu2" ||
                commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirst" ||
                commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.WsContractFirstContextMenu")
            {
                handled = ProcessCodeGenerationRequest(String.Empty);
                return;
            }
            else if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.CreateWsdlContextMenu")
            {
                handled = ProcessWsdlWizardRequest(false);
                return;
            }
            else if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.EditWsdlContextMenu")
            {
                handled = ProcessWsdlWizardRequest(true);
                return;
            }
            else if (commandName == "Thinktecture.Tools.Web.Services.ContractFirst.Connect.GenerateCodeMenu")
            {
                handled = ProcessXsdCodeGenerationRequest();
                return;
            }

            AppLog.LogMessage("Leaving Exec method");
        }

        private bool ProcessWsdlWizardRequest(bool roundtrip)
        {
            if (applicationObject.SelectedItems.Count > 0 && applicationObject.SelectedItems.SelectionContainer.Count > 0)
            {
                SelectedItem item = applicationObject.SelectedItems.Item(1);
                string itemName = item.Name;
                string currentDir = "";
                string itemRelativePath = "";
                string projectRootDir = "";

                // BDS: Changed this code to obtain the item's relative path.
                if (item.ProjectItem != null)
                {
                    if (item.ProjectItem.ContainingProject.FileName.Length == 0)
                    {
                        MessageBox.Show("Cannot create a WSDL contract for items outside of a project.",
                            "Web Services Contract-First WSDL Wizard", MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation);

                        return true;
                    }

                    Project project = GetProject();
                    currentDir = project.Properties.Item("FullPath").Value.ToString();
                    // currentDir = new FileInfo(item.ProjectItem.ContainingProject.FileName).DirectoryName;

                    projectRootDir = currentDir;
                    // itemRelativePath = currentDir;

                    if (item.ProjectItem.FileCount > 0)
                    {
                        currentDir = new FileInfo(item.ProjectItem.get_FileNames(0)).DirectoryName;
                        // itemRelativePath = currentDir.Replace(itemRelativePath, "");
                    }
                }
                else
                {
                    Project project = GetProject();
                    currentDir = project.Properties.Item("FullPath").Value.ToString();

                    // currentDir = new FileInfo(item.Project.FullName).DirectoryName;
                    projectRootDir = currentDir;
                    // itemRelativePath = currentDir.Substring(projectDir.LastIndexOf("\\") + 1);
                }

                // BDS: Remove the first char if it is a back slash. 
                // Then change the back slashes to forward slashes in the relative path.
                //if(itemRelativePath.StartsWith("\\"))
                //{
                //	itemRelativePath = itemRelativePath.Substring(1);
                //}
                //itemRelativePath = itemRelativePath.Replace("\\", "/");

                string metdataFile = currentDir + @"\" + itemName;
                WsdlWizardForm wizard = null;

                try
                {
                    if (roundtrip)
                        wizard = new WsdlWizardForm(metdataFile, true);
                    else
                        wizard = new WsdlWizardForm(metdataFile);
                    wizard.WsdlLocation = currentDir;
                    wizard.DefaultPathForImports = itemRelativePath;
                    wizard.ProjectRootDirectory = projectRootDir;
                    wizard.ShowDialog();

                    string wsdlFile = "";
                    if (wizard.DialogResult == DialogResult.OK)
                    {
                        if (wizard.WsdlLocation.Length > 0)
                        {
                            wsdlFile = wizard.WsdlLocation;

                            // BDS: Fixed a bug here. We did not check the round-tripping mode before we 
                            // create the file. This caused the wizard to create duplicate .wsdl files 
                            // in the project root folder.
                            if (!roundtrip)
                            {
                                AddNewFileToProject(wsdlFile);
                            }

                            if (wizard.OpenCodeGenDialog)
                            {
                                ProcessCodeGenerationRequest(wsdlFile);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message,
                        "WSDL Wizard", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    wizard.Close();
                    return false;
                }
            }

            return true;
        }

        private bool ProcessCodeGenerationRequest(string wsdlFromWizard)
        {
            try
            {
                if ((applicationObject.SelectedItems.Count > 0 &&
                    applicationObject.SelectedItems.SelectionContainer != null &&
                    applicationObject.SelectedItems.SelectionContainer.Count > 0) ||
                    wsdlFromWizard.Length != 0)
                {
                    Project project = GetProject();

                    // No project is currently selected. So display a message box.
                    if (project == null)
                    {
                        MessageBox.Show("WSCF could not detect a selected WSDL file or a project.",
                                    "Web Services Contract-First code generation", MessageBoxButtons.OK,
                                    MessageBoxIcon.Exclamation);
                        return true;
                    }

                    if (project.FileName.Length == 0)
                    {
                        MessageBox.Show(
                            "Cannot generate code for items outside of a project.",
                            "Web Services Contract-First code generation",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation);

                        return true;
                    }

                    SelectedItem item = applicationObject.SelectedItems.Item(1);
                    string itemPath = "";
                    string outputDirectory = "";
                    string projectName = project.Name;
                    string projectDefaultNamespace = "";
                    string wsdlName = "";
                    string projectRootDir;

                    // Read the full path from the project properties. 
                    projectRootDir = project.Properties.Item("FullPath").Value.ToString();

                    if (wsdlFromWizard.Length > 0)
                    {
                        itemPath = wsdlFromWizard;
                    }
                    else
                    {
                        // Project item is selected. So obtain the file path.
                        if (item.ProjectItem != null)
                        {
                            if (item.ProjectItem.FileCount > 0)
                            {
                                itemPath = item.ProjectItem.get_FileNames(1);
                            }
                        }
                    }

                    if (itemPath != "")
                    {
                        if (itemPath.EndsWith(".wsdl"))
                        {
                            wsdlName = WsdlHelper.GetWsdlNameFromLocalFile(itemPath);
                        }
                        else
                        {
                            MessageBox.Show("WSCF could not detect a selected WSDL file.",
                                    "Web Services Contract-First code generation", MessageBoxButtons.OK,
                                    MessageBoxIcon.Exclamation);

                            return true;
                        }
                    }
                    else
                    {
                        if (IsWebProject())
                        {
                            wsdlName = "WebService";
                        }
                        else
                        {
                            wsdlName = project.Name;
                        }
                    }

                    WebServiceCodeGenDialogNew dialogForm =
                        new WebServiceCodeGenDialogNew();

                    dialogForm.WsdlLocation = itemPath;
                    dialogForm.NamespaceProxy = wsdlName;
                    dialogForm.NamespaceStub = wsdlName;
                    dialogForm.ProxyFilename = wsdlName + "Proxy";
                    dialogForm.StubFilename = wsdlName;

                    dialogForm.ShowDialog();

                    string wsdlSource = "";

                    if (dialogForm.DialogResult == DialogResult.OK)
                    {
                        Cursor.Current = Cursors.WaitCursor;
                        string downloadedFile = null;

                        // Read and save the WSDL from the remote endpoint.                    
                        if (dialogForm.WsdlLocation.ToLower(CultureInfo.CurrentCulture).IndexOf("http://") > -1 ||
                            dialogForm.WsdlLocation.ToLower(CultureInfo.CurrentCulture).IndexOf("https://") > -1)
                        {
                            try
                            {
                                if (WsdlHelper.RequireSslCertificate(new Uri(dialogForm.WsdlLocation)))
                                {
                                    MessageBox.Show(null, "WARNING! You are about to access a resource which requires a security certificate. This certificate was issued by a company you have not chosen to trust.", "WSCF", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                                }

                                wsdlSource = WsdlHelper.GetWsdlFromUri(new Uri(dialogForm.WsdlLocation));
                            }
                            catch (Exception ex)
                            {
                                throw new CodeGenerationException("An error occured while reading the WSDL.", ex);
                            }

                            wsdlName = WsdlHelper.GetLocalWsdlFilename(new Uri(dialogForm.WsdlLocation), wsdlSource);

                            if (!wsdlName.EndsWith(".wsdl", StringComparison.CurrentCultureIgnoreCase))
                            {
                                downloadedFile = AppendFilePaths(projectRootDir, wsdlName + ".wsdl");
                            }
                            else
                            {
                                downloadedFile = AppendFilePaths(projectRootDir, wsdlName);
                                wsdlName = wsdlName.Substring(0, wsdlName.Length - 5);
                            }

                            StreamWriter writer = new StreamWriter(downloadedFile, false, Encoding.UTF8);
                            writer.Write(wsdlSource);
                            writer.Close();

                            project.ProjectItems.AddFromFile(downloadedFile);
                            itemPath = dialogForm.WsdlLocation;
                        }
                        else
                        {
                            // Make sure that we read the path of the WSDL file which is selected
                            // using the 'Browse' button on the dialog box.
                            if (string.IsNullOrEmpty(itemPath))
                            {
                                itemPath = dialogForm.WsdlPath;
                            }

                            wsdlSource = WsdlHelper.GetWsdlFromFile(itemPath);
                        }

                        string orginalFile;

                        if (string.IsNullOrEmpty(downloadedFile))
                        {
                            orginalFile = itemPath;
                        }
                        else
                        {
                            orginalFile = downloadedFile;
                        }

                        string translatedWsdlFilename = orginalFile.Replace(".wsdl", "_transformed.wsdl");

                        try
                        {
                            if (Rpc2DocumentLiteralTranslator.ContainsRpcLiteralBindings(orginalFile))
                            {
                                Rpc2DocumentLiteralTranslator r2d =
                                    Rpc2DocumentLiteralTranslator.Translate(
                                    orginalFile,
                                    translatedWsdlFilename);

                                itemPath = translatedWsdlFilename;
                            }
                        }
                        catch (Rpc2DocumentLiteralTranslationException ex)
                        {
                            throw new CodeGenerationException("An error occured while generating code for a WSDL.", ex);
                        }
                        catch
                        {
                            throw new CodeGenerationException("An error occured while generating code for a WSDL.");
                        }

                        // BDS 11/24/2005: Check whether the project is a web project 
                        // or not and create the project root directory and output 
                        // directory appropriatly. 
                        if (!IsWebProject())
                        {
                            // BDS 11/24/2005: This block is for regular projects.
                            if (item.ProjectItem != null)
                            {
                                if (item.ProjectItem.FileCount > 0)
                                {
                                    outputDirectory = new FileInfo(
                                        item.ProjectItem.get_FileNames(1)).Directory.FullName;

                                    // If the selected item is a linked item, select the containing
                                    // project directory as the outputDirectory.
                                    if (!outputDirectory.StartsWith(projectRootDir))
                                    {
                                        ProjectItem parentFolder = item.ProjectItem.Collection.Parent as ProjectItem;

                                        if (parentFolder != null)
                                        {
                                            if (parentFolder.FileCount > 0)
                                            {
                                                outputDirectory = new FileInfo(parentFolder.get_FileNames(1)).Directory.FullName;
                                            }
                                        }
                                        else
                                        {
                                            outputDirectory = projectRootDir;
                                        }
                                    }

                                }
                                else
                                {
                                    outputDirectory = projectRootDir;
                                }
                            }
                            else
                            {
                                outputDirectory = projectRootDir;
                            }
                        }
                        else
                        {
                            // BDS 11/24/2005: This block is for web projects.                        
                            VSWebSite website = (VSWebSite)project.Object;
                            ProjectItem codeFolder = website.CodeFolders.Add(
                                string.Format(@"App_Code/{0}", wsdlName));
                            outputDirectory = AppendFilePaths(projectRootDir, @"App_Code\" + wsdlName);
                        }

                        projectDefaultNamespace = GetAssemblyRootNamespace();

                        bool sc = dialogForm.ServiceCode;
                        bool cc = dialogForm.ClientCode;
                        string projectLanguage = "";

                        string proxyCode = "";

                        string codeNamespaceProxy = dialogForm.NamespaceProxy;
                        string codeNamespaceStub = dialogForm.NamespaceStub;
                        bool genProps = dialogForm.GenerateProperties;
                        bool accessSOAP = dialogForm.AccessSoap;
                        bool endpointConfig = dialogForm.EndpointConfig;
                        bool webProject = IsWebProject();
                        bool clientSide = ((accessSOAP || endpointConfig) && !webProject);
                        bool serviceSide = sc;
                        bool needConfig = accessSOAP || endpointConfig || sc;
                        bool serializable = dialogForm.SerializableClasses;
                        bool enableValidation = dialogForm.EnableValidate;
                        bool generateCollections = dialogForm.Collections;
                        // BDS: Added these variables to hold new preferences.
                        bool generateMultipleFiles = dialogForm.GenerateMultipleFiles;
                        string assemblyName = GetAssemblyName();
                        bool generateInterface = true; // TODO: Read the value from the UI.
                        bool generateHelp = true;	   // TODO: Read the value from the UI.		
                        // BDS: Reset the addDuplicatedTypesAlert.
                        this.addDuplictedTypesAlert = false;
                        // BDS: Read the overwrite files option from the dialog box.
                        this.overwriteFiles = dialogForm.Overwrite;
                        string asmName = GetAssemblyName();	// BDS: The assembly name.                    
                        bool changeCasing = dialogForm.ChangeCasing;

                        // Check whether the "Enable WSDL" option is applicable.
                        // This option is only applicable when the WSDL resides within the 
                        // project's root directory.                            
                        bool enableWsdl = false;

                        if (dialogForm.EnableWsdl)
                        {
                            if (!itemPath.StartsWith(projectRootDir, StringComparison.CurrentCultureIgnoreCase))
                            {
                                MessageBox.Show(null, "Selected WSDL file does not reside in the project directory. \"Enable WSDL\" option will be omitted.",
                                    "WSCF", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            }
                            else
                            {
                                enableWsdl = true;
                            }
                        }

                        bool enableDataBinding = dialogForm.EnableDataBinding;
                        bool orderIdentifiers = dialogForm.OrderIdentifiers;
                        bool oldAsyncCode = dialogForm.OldAsyncCode;
                        bool noXxxSpecifiedHandling = dialogForm.NoXxxSpecifiedHandling;
                        bool useGenericList = dialogForm.GenericList;

                        switch (project.Kind)
                        {
                            case PrjKind.prjKindVBProject:
                                projectLanguage = "vb";
                                // BDS: For VB - do not use a namespace name if the specified one is same as 
                                // the default one.
                                if (codeNamespaceProxy.ToLower() == projectDefaultNamespace.ToLower())
                                {
                                    codeNamespaceProxy = "";
                                }
                                if (codeNamespaceStub.ToLower() == projectDefaultNamespace.ToLower())
                                {
                                    codeNamespaceStub = "";
                                }
                                break;
                            case PrjKind.prjKindCSharpProject:
                                projectLanguage = "cs";
                                break;
                            default:
                                projectLanguage = GetWebSiteLanguage();
                                break;
                        }

                        string asmxCodeFile = "";
                        string relativeWsdlPath = null;

                        if (!itemPath.StartsWith(@"http://") && !itemPath.StartsWith(@"https://"))
                        {
                            relativeWsdlPath = IOPathHelper.GetRelativePath(
                                itemPath, projectRootDir);
                        }
                        else
                        {
                            relativeWsdlPath = itemPath;
                        }

                        if (IsWebProject())
                        {
                            asmxCodeFile = "~/App_Code/" + wsdlName + "/" +
                                dialogForm.StubFilename + "." + projectLanguage;
                        }
                        else
                        {
                            asmxCodeFile = dialogForm.StubFilename + ".asmx." + projectLanguage;
                        }

                        bool configExists = false;
                        string configFilePath = "";

                        try
                        {

                            WebServiceCodeGenerator gen = new WebServiceCodeGenerator(
                                itemPath,
                                projectLanguage,
                                genProps,
                                projectRootDir,
                                accessSOAP,
                                endpointConfig,
                                clientSide,
                                serializable,
                                enableValidation,
                                generateCollections,
                                wsdlSource,
                                asmxCodeFile,
                                generateMultipleFiles,
                                dialogForm.ProxyFilename,
                                dialogForm.StubFilename,
                                generateInterface,
                                generateHelp,
                                asmName,
                                changeCasing,
                                enableWsdl,
                                relativeWsdlPath,
                                enableDataBinding,
                                orderIdentifiers,
                                oldAsyncCode,
                                noXxxSpecifiedHandling,
                                useGenericList);

                            // BDS: Added this code to pass the assembly 
                            // root namespace to the code generator.
                            gen.AssemblyRootNamespace = projectDefaultNamespace;

                            if (cc)
                            {
                                configFilePath = AppendFilePaths(projectRootDir, @"App.config");
                                // Determine whether the config file already exists or not. 
                                configExists = File.Exists(configFilePath);

                                // BDS: Changed the code here to read the SourceFile objects from the 
                                // SourceFiles collection and generate the files.
                                SourceFiles files = gen.GenerateProxyCode(codeNamespaceProxy);

                                // BDS: Display warnings.
                                DisplayWarnings(gen.Warnings);

                                string codeFile = string.Empty;
                                foreach (SourceFile file in files)
                                {
                                    proxyCode = file.SourceCode;
                                    codeFile = AppendFilePaths(outputDirectory, file.FileName);
                                    WriteCodeToFile(codeFile, proxyCode, projectLanguage);
                                }

                                if (endpointConfig)
                                {
                                    Window win = applicationObject.Windows.Item(Constants.vsWindowKindTaskList);
                                    win.Activate();

                                    TaskList taskList = (TaskList)win.Object;

                                    bool itemExist = false;

                                    for (int ti = 1; ti <= taskList.TaskItems.Count; ti++)
                                    {
                                        TaskItem existingItem = taskList.TaskItems.Item(ti);

                                        if (existingItem.SubCategory == "WSCFA1")
                                        {
                                            itemExist = true;
                                            break;
                                        }
                                    }

                                    if (!itemExist)
                                    {
                                        TaskItem tlItem;
                                        tlItem = taskList.TaskItems.Add(
                                            "BuildCompile", "WSCFA1",
                                            "WSCF: check application configuration file for correct Web Service endpoint URL.",
                                            vsTaskPriority.vsTaskPriorityHigh,
                                            vsTaskIcon.vsTaskIconUser, true, "", 0, true, true);
                                    }

                                    ActivateTaskBar();

                                }
                            }
                            if (sc)
                            {
                                configFilePath = AppendFilePaths(projectRootDir, @"Web.config");
                                // Determine whether the config file already exists or not. 
                                configExists = File.Exists(configFilePath);

                                // BDS: Changed the code here to read the SourceFile objects from the 
                                // SourceFiles collection and generate the files.
                                SourceFiles files = gen.GenerateStubCode(codeNamespaceStub);

                                // BDS: Display warnings.
                                DisplayWarnings(gen.Warnings);

                                string codeFile = string.Empty;
                                foreach (SourceFile file in files)
                                {
                                    // Modified this iteration to write the AsmxHelpModule to project root 
                                    // directory.
                                    if (!file.AsmxDeclarative && !file.AspxHelpPage &&
                                        !file.AsmxHelpModule && !file.ServiceImplementation)
                                    {
                                        codeFile = AppendFilePaths(outputDirectory, file.FileName);
                                        WriteCodeToFile(codeFile, file.SourceCode, projectLanguage);
                                    }
                                    else if (file.AsmxHelpModule)
                                    {
                                        // BDS: Write the ASMX help module to the code directory
                                        // if the project is a web project.
                                        if (!IsWebProject())
                                        {
                                            codeFile = AppendFilePaths(projectRootDir, file.FileName);
                                        }
                                        else
                                        {
                                            codeFile = AppendFilePaths(projectRootDir, @"App_Code\" + file.FileName);
                                        }
                                        WriteCodeToFile(codeFile, file.SourceCode, projectLanguage);
                                    }
                                    else if (file.AspxHelpPage)
                                    {
                                        WriteCodeToFile(AppendFilePaths(projectRootDir, file.FileName), file.SourceCode,
                                            projectLanguage);
                                    }
                                }

                                SourceFile asmxFile = files.AsmxFile;
                                SourceFile asmxCodebehind = files.ServiceImplementation;

                                if (IsWebProject())
                                {
                                    WriteCodeToFile(AppendFilePaths(projectRootDir, dialogForm.StubFilename),
                                        asmxFile.SourceCode, "asmx");
                                    WriteCodeToFile(AppendFilePaths(outputDirectory, dialogForm.StubFilename),
                                        asmxCodebehind.SourceCode, projectLanguage);
                                }
                                else
                                {
                                    WriteASMXCodeToFile(AppendFilePaths(projectRootDir, dialogForm.StubFilename),
                                        asmxCodebehind.SourceCode, asmxFile.SourceCode, projectLanguage);
                                }

                            }

                            // BDS: Add the duplicated types alert if there is any duplicated file.						
                            if (this.addDuplictedTypesAlert)
                            {
                                Window win = applicationObject.Windows.Item(Constants.vsWindowKindTaskList);
                                win.Activate();
                                TaskList taskList = (TaskList)win.Object;
                                bool itemExist = false;

                                for (int ti = 1; ti <= taskList.TaskItems.Count; ti++)
                                {
                                    TaskItem existingItem = taskList.TaskItems.Item(ti);

                                    if (existingItem.SubCategory == "WSCFA2")
                                    {
                                        itemExist = true;
                                        break;
                                    }
                                }

                                if (!itemExist)
                                {
                                    TaskItem tlItem;
                                    tlItem = taskList.TaskItems.Add(
                                        "BuildCompile", "WSCFA2",
                                        "WSCF: An attempt to overwrite an existing file was detected. Check for possible type duplications.",
                                        vsTaskPriority.vsTaskPriorityHigh,
                                        vsTaskIcon.vsTaskIconUser, true, "", 0, true, true);
                                }
                                ActivateTaskBar();
                            }

                            AddAssembliesToProject(accessSOAP, enableValidation);
                            if (needConfig)
                                AddConfigFilesToProject(projectRootDir, clientSide, serviceSide);

                            MessageBox.Show("Code was generated successfully.",
                                "Web Services Contract-First code generation", MessageBoxButtons.OK,
                                MessageBoxIcon.Information);
                        }
                        catch (Exception ex)
                        {
                            // Delete the config file if it did not exisit before the last code-gen.
                            if (!configExists)
                            {
                                File.Delete(configFilePath);
                                Trace.WriteLine("Configuration file deleted: " + configFilePath, "ERROR");
                            }

                            string errorMessage = ex.Message;
                            if (ex.InnerException != null)
                            {
                                errorMessage = ex.Message + " " + ex.InnerException.Message;

                                if (ex.InnerException.Message.StartsWith("Unable to import"))
                                {
                                    errorMessage = errorMessage + "\nThis error may occur due to one of the following reasons.\n";
                                    errorMessage = errorMessage + "1. Missing or invalid schema location for one of the imported schemas.\n";
                                    errorMessage = errorMessage + "2. Missing type definition in the imported schema.";
                                }
                            }

                            MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "An error occured. Details: {0}", errorMessage),
                                "Web Services Contract-First code generation", MessageBoxButtons.OK,
                                MessageBoxIcon.Error);

                            throw new CodeGenerationException("An error occured while generating code from WSDL.", ex);
                        }

                        return true;
                    }
                }
                else
                {
                    MessageBox.Show("WSCF could not detect a selected WSDL file or a project.",
                                    "Web Services Contract-First code generation", MessageBoxButtons.OK,
                                    MessageBoxIcon.Exclamation);
                }

                return false;
            }
            catch (Exception ex)
            {
                string errorMsg = "An error occrred while trying to generate code.";
                string des = WscfConfiguration.AppSettings["detailedErrors"];

                if (des != null && des.ToLower() == "true")
                {
                    errorMsg += "\r\nDetails: " + ex.Message;
                }
                else
                {
                    errorMsg += "\r\nTurn on the detailed error message to view more information.";
                }

                MessageBox.Show(null, errorMsg, "WSCF", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return false;

        } // End of ProcessCodeGenerationRequestFunction.

        private bool ProcessXsdCodeGenerationRequest()
        {
            try
            {
                if (applicationObject.SelectedItems.Count > 0 &&
                    applicationObject.SelectedItems.SelectionContainer != null &&
                    applicationObject.SelectedItems.SelectionContainer.Count > 0)
                {
                    Project project = GetProject();

                    // No project is currently selected. So display a message box.
                    if (project == null)
                    {
                        MessageBox.Show("WSCF could not detect a selected WSDL file or a project.",
                                    "Web Services Contract-First code generation", MessageBoxButtons.OK,
                                    MessageBoxIcon.Exclamation);
                        return true;
                    }

                    if (project.FileName.Length == 0)
                    {
                        MessageBox.Show(
                            "Cannot generate code for items outside of a project.",
                            "Web Services Contract-First code generation",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation);

                        return true;
                    }

                    SelectedItem item = applicationObject.SelectedItems.Item(1);
                    string projectName = project.Name;
                    string projectDefaultNamespace = GetAssemblyRootNamespace();
                    string projectRootDir = project.Properties.Item("FullPath").Value.ToString();
                    string itemPath = "";
                    string outputfile = "";
                    string outputDirectory;
                    string projectlanguage;

                    switch (project.Kind)
                    {
                        case PrjKind.prjKindVBProject:
                            projectlanguage = "vb";
                            break;
                        case PrjKind.prjKindCSharpProject:
                            projectlanguage = "cs";
                            break;
                        default:
                            projectlanguage = GetWebSiteLanguage();
                            break;
                    }

                    // Project item is selected. So obtain the file path.
                    if (item.ProjectItem != null)
                    {
                        if (item.ProjectItem.FileCount > 0)
                        {
                            itemPath = item.ProjectItem.get_FileNames(1);
                        }
                    }

                    string itemfnameonly = Path.GetFileNameWithoutExtension(itemPath);
                    if (projectlanguage == "vb")
                        outputfile = itemfnameonly + ".vb";
                    else if (projectlanguage == "cs")
                        outputfile = itemfnameonly + ".cs";

                    string[] xsdfiles = { itemPath }; // Currently we support only one file.
                    XsdCodeGenDialog dialogForm = new XsdCodeGenDialog(xsdfiles, projectDefaultNamespace, outputfile);
                    dialogForm.ShowDialog();

                    if (dialogForm.DialogResult == DialogResult.OK)
                    {
                        Cursor.Current = Cursors.WaitCursor;

                        // BDS 11/24/2005: Check whether the project is a web project 
                        // or not and create the project root directory and output 
                        // directory appropriatly. 
                        if (!IsWebProject())
                        {
                            // BDS 11/24/2005: This block is for regular projects.
                            if (item.ProjectItem != null)
                            {
                                if (item.ProjectItem.FileCount > 0)
                                {
                                    outputDirectory = new FileInfo(
                                        item.ProjectItem.get_FileNames(1)).Directory.FullName;

                                    // If the selected item is a linked item, select the containing
                                    // project directory as the outputDirectory.
                                    if (!outputDirectory.StartsWith(projectRootDir))
                                    {
                                        ProjectItem parentFolder = item.ProjectItem.Collection.Parent as ProjectItem;

                                        if (parentFolder != null)
                                        {
                                            if (parentFolder.FileCount > 0)
                                            {
                                                outputDirectory = new FileInfo(parentFolder.get_FileNames(1)).Directory.FullName;
                                            }
                                        }
                                        else
                                        {
                                            outputDirectory = projectRootDir;
                                        }
                                    }

                                }
                                else
                                {
                                    outputDirectory = projectRootDir;
                                }
                            }
                            else
                            {
                                outputDirectory = projectRootDir;
                            }
                        }
                        else
                        {
                            // BDS 11/24/2005: This block is for web projects.                        
                            VSWebSite website = (VSWebSite)project.Object;
                            ProjectItem codeFolder = website.CodeFolders.Add(@"App_Code");
                            outputDirectory = AppendFilePaths(projectRootDir, @"App_Code");
                        }

                        bool genProps = dialogForm.PublicProperties;
                        bool webProject = IsWebProject();
                        bool serializable = dialogForm.SerializableClasses;
                        bool generateCollections = dialogForm.Collections;
                        bool generateMultipleFiles = dialogForm.GenerateMultipleFiles;
                        this.overwriteFiles = dialogForm.OverwriteFiles;
                        bool changeCasing = dialogForm.AdjustCasing;
                        bool enableDataBinding = dialogForm.DataBinding;
                        bool orderIdentifiers = dialogForm.OrderIdentifiers;
                        bool noXxxSpecifiedHandling = dialogForm.NoXxxSpecifiedHandling;
                        bool useGenericList = dialogForm.GenericLists;
                        string ns = dialogForm.Namespace;
                        string xsdoutputfilename = dialogForm.TargetFileName;

                        // TODO: Need to get this from the UI.
                        bool removeDefaultValueAttribute = false;

                        try
                        {
                            WebServiceCodeGenerator gen = new WebServiceCodeGenerator(projectlanguage,
                                                                                      xsdoutputfilename,
                                                                                      genProps,
                                                                                      serializable,
                                                                                      generateCollections,
                                                                                      useGenericList,
                                                                                      enableDataBinding,
                                                                                      orderIdentifiers,
                                                                                      changeCasing,
                                                                                      noXxxSpecifiedHandling,
                                                                                      generateMultipleFiles,
                                                                                      removeDefaultValueAttribute);
                            SourceFiles files = gen.GenerateDataContracts(xsdfiles, ns);
                            DisplayWarnings(gen.Warnings);

                            foreach (SourceFile file in files)
                            {
                                string code = file.SourceCode;
                                string codeFile = AppendFilePaths(outputDirectory, file.FileName);
                                WriteCodeToFile(codeFile, code, projectlanguage);
                            }

                            // BDS: Add the duplicated types alert if there is any duplicated file.						
                            if (this.addDuplictedTypesAlert)
                            {
                                Window win = applicationObject.Windows.Item(Constants.vsWindowKindTaskList);
                                win.Activate();
                                TaskList taskList = (TaskList)win.Object;
                                bool itemExist = false;

                                for (int ti = 1; ti <= taskList.TaskItems.Count; ti++)
                                {
                                    TaskItem existingItem = taskList.TaskItems.Item(ti);

                                    if (existingItem.SubCategory == "WSCFA2")
                                    {
                                        itemExist = true;
                                        break;
                                    }
                                }

                                if (!itemExist)
                                {
                                    TaskItem tlItem;
                                    tlItem = taskList.TaskItems.Add(
                                        "BuildCompile", "WSCFA2",
                                        "WSCF: An attempt to overwrite an existing file was detected. Check for possible type duplications.",
                                        vsTaskPriority.vsTaskPriorityHigh,
                                        vsTaskIcon.vsTaskIconUser, true, "", 0, true, true);
                                }
                                ActivateTaskBar();
                            }

                            MessageBox.Show("Code was generated successfully.",
                                "Web Services Contract-First code generation", MessageBoxButtons.OK,
                                MessageBoxIcon.Information);
                        }
                        catch (Exception ex)
                        {
                            string errorMessage = ex.Message;
                            if (ex.InnerException != null)
                            {
                                errorMessage = ex.Message + " " + ex.InnerException.Message;

                                if (ex.InnerException.Message.StartsWith("Unable to import"))
                                {
                                    errorMessage = errorMessage + "\nThis error may occur due to one of the following reasons.\n";
                                    errorMessage = errorMessage + "1. Missing or invalid schema location for one of the imported schemas.\n";
                                    errorMessage = errorMessage + "2. Missing type definition in the imported schema.";
                                }
                            }

                            MessageBox.Show(string.Format(CultureInfo.CurrentCulture,
                                                          "An error occured. Details: {0}",
                                                          errorMessage),
                                            "Web Services Contract-First code generation",
                                            MessageBoxButtons.OK,
                                            MessageBoxIcon.Error);
                        }

                        return true;
                    }
                }
                else
                {
                    MessageBox.Show("WSCF could not detect a selected XSD file.",
                                    "Web Services Contract-First code generation",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Exclamation);
                }

                return false;
            }
            catch (Exception ex)
            {
                string errorMsg = "An error occrred while trying to generate code.";
                string des = WscfConfiguration.AppSettings["detailedErrors"];

                if (des != null && des.ToLower() == "true")
                {
                    errorMsg += "\r\nDetails: " + ex.Message;
                }
                else
                {
                    errorMsg += "\r\nTurn on the detailed error message to view more information.";
                }

                MessageBox.Show(null, errorMsg, "WSCF", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return false;

        } // End of ProcessXsdCodeGenerationRequestFunction.

        #region Private helper methods

        private string AppendFilePaths(string path1, string path2)
        {
            string newPath;

            if (path1.EndsWith("\\"))
            {
                newPath = path1 + path2;
            }
            else
            {
                newPath = string.Format("{0}\\{1}", path1, path2);
            }

            return newPath;
        }

        private void ActivateTaskBar()
        {
            object cin = "Add-ins and Macros";
            object cout = new object();

            applicationObject.Commands.Raise("{1496A755-94DE-11D0-8C3F-00C04FC2AAE2}", 2200,
                    ref cin, ref cout);
        }

        // BDS 11/23/2005: Re-engineered this function to fit into the 
        // new Web Project in VS 2005.
        private bool IsWebProject()
        {
            Project project = GetProject();
            return (project.Object is VSWebSite);
        }

        /// <summary>
        /// This function returns the default programming language for
        /// currently selected project.
        /// </summary>
        /// <returns></returns>
        private string GetWebSiteLanguage()
        {
            Project project = GetProject();

            if (IsWebProject())
            {
                string lang = project.Properties.Item("CurrentWebSiteLanguage").Value.ToString();

                switch (lang)
                {
                    case "Visual Basic":
                        lang = "vb";
                        break;
                    case "Visual C#":
                        lang = "cs";
                        break;
                    default:
                        lang = "cs";
                        break;
                }

                return lang;
            }

            return "";
        }

        /// <summary>
        /// This method returns the assembly name of the selected project file.
        /// </summary>
        /// <returns>A string value.</returns>
        /// <author>BDS - thinktecture</author>
        private string GetAssemblyName()
        {
            SelectedItem item = applicationObject.SelectedItems.Item(1);
            try
            {
                string assemblyName = "";
                if (item.ProjectItem != null)
                    assemblyName = item.ProjectItem.ContainingProject.Properties.Item("AssemblyName").Value.ToString();
                else
                    assemblyName = item.Project.Properties.Item("AssemblyName").Value.ToString();

                return assemblyName;
            }
            catch (Exception)
            {
                // BDS 11/22/2005: Do not throw here. Because web projects
                // will defintly throw. Therefore return an empty string
                // for the assembly name.

                //throw new VSProjectException(
                //    "An error occured while determining project type.", ex);
            }

            return "";
        }

        /// <summary>
        /// This method returns the assembly root namespace of the selected project file.
        /// </summary>
        /// <returns>A string value.</returns>
        /// <author>BDS - thinktecture</author>
        private string GetAssemblyRootNamespace()
        {
            SelectedItem item = applicationObject.SelectedItems.Item(1);
            try
            {
                string namespaceName = "";
                if (item.ProjectItem != null)
                    namespaceName = item.ProjectItem.ContainingProject.Properties.Item("DefaultNamespace").Value.ToString();
                else
                    namespaceName = item.Project.Properties.Item("DefaultNamespace").Value.ToString();

                return namespaceName;
            }
            catch (Exception)
            {
                // BDS 11/22/2005: Do not re-throw. Because
                // web projects will always throw. Therefore handle this 
                // exception and return an empty string.
                // throw new VSProjectException(
                //  "An error occured while determining project type.", ex);
            }

            return "";
        }

        private void WriteCodeToFile(string fileName, string code, string projectLanguage)
        {
            // BDS: ASPX file indicator.
            bool isAspx = false;
            string codeFile = string.Empty;

            // BDS: Check whether the file is an aspx or not.
            if (fileName.ToLower().IndexOf(".aspx") < 0)
            {
                fileName = fileName.Replace("." + projectLanguage, "");

                codeFile = fileName + ".";
                codeFile += projectLanguage;
            }
            else
            {
                isAspx = true; // BDS: Turn on the aspx file indicator.
                codeFile = fileName;
            }

            // BDS: Is this file aspx or the custom http module created to handle aspx requests?
            if (!isAspx && !codeFile.EndsWith("AsmxHelpModule.cs"))
            {
                codeFile = GetNextFileName(codeFile);
            }

            StreamWriter writer = new StreamWriter(codeFile, false);
            try
            {
                writer.Write(code);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "Error when generating source code: {0}", ex.Message),
                    "Web Services Contract-First code generation", MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);

                throw new FileAccessException("An error occured while writing file to disc.", ex);
            }
            finally
            {
                writer.Close();
            }

            // Add to the project if not already present
            if (applicationObject.Solution.FindProjectItem(codeFile) == null)
            {
                try
                {
                    Project selectedProject = GetProject();
                    selectedProject.ProjectItems.AddFromFile(codeFile);

                    //
                    // BDS: If the file is an aspx then remove the code behind page and
                    // the resource file associated with it.
                    // Also remove the <%@ Page %> directive from the aspx file.
                    //
                    if (isAspx)
                    {
                        // Remove the code behind page.
                        ProjectItem aspxcs = applicationObject.Solution.FindProjectItem(codeFile + "." + projectLanguage);
                        if (aspxcs != null)
                        {
                            aspxcs.Remove();	// Remove the file from the project.
                            File.Delete(codeFile + "." + projectLanguage); // Permanently delete the file.							
                            File.Delete(codeFile + ".resx"); // Permanently delete the resource the file.
                        }

                        // Find and remove the <%@ Page %> directive.
                        StreamReader sr = new StreamReader(codeFile);
                        string codeInFile = sr.ReadToEnd();
                        sr.Close();
                        int start = codeInFile.IndexOf("<%@ Page");
                        int end = 0;
                        if (start >= 0)
                        {
                            end = codeInFile.IndexOf("%>") + 2;
                            string pageDirective = codeInFile.Substring(start, (end - start));
                            codeInFile = codeInFile.Replace(pageDirective, string.Empty);

                            StreamWriter sw = new StreamWriter(codeFile);
                            sw.Write(codeInFile);
                            sw.Close();
                        }

                        // Refresh solution explorer window to remove the 
                        // deleted files from the tree view.                        
                        if (IsWebProject())
                        {
                            VSWebSite website = (VSWebSite)selectedProject.Object;
                            website.Refresh();
                        }
                        else
                        {
                            VSProject2 regularPrj = (VSProject2)selectedProject.Object;
                            regularPrj.Refresh();
                        }

                    }
                    //
                    // BDS: End of aspx extra files clean-up.
                    //
                }
                catch (Exception ex)
                {
                    throw new FileAccessException("An error occured while adding file to VS.NET project.", ex);
                }
            }
        }

        private void WriteASMXCodeToFile(string fileName, string code, string decl, string projectLanguage)
        {
            fileName = fileName.Replace("." + projectLanguage, "");

            string codeFile = fileName + ".asmx." + projectLanguage;
            string declFile = fileName + ".asmx";

            // BDS: Fixed a bug here. We did not avoid overwriting the .asmx endpoint files.
            declFile = GetNextFileName(declFile);
            codeFile = declFile + "." + projectLanguage;

            StreamWriter writer = new StreamWriter(codeFile, false);
            try
            {
                writer.Write(code);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "Error when generating source code: {0}", ex.Message),
                    "Web Services Contract-First code generation", MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);

                throw new FileAccessException("An error occured while writing a file to disc.", ex);
            }
            finally
            {
                writer.Close();
            }

            writer = new StreamWriter(declFile, false);
            try
            {
                writer.Write(decl);
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format(CultureInfo.CurrentCulture, "Error when generating source code: {0}", ex.Message),
                    "Web Services Contract-First code generation", MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);

                throw new FileAccessException("An error occured while writing a file to disc.", ex);
            }
            finally
            {
                writer.Close();
            }

            // Add to the project if not already present
            Project project = GetProject();

            if (applicationObject.Solution.FindProjectItem(codeFile) == null)
            {
                try
                {
                    project.ProjectItems.AddFromFile(codeFile);
                }
                catch (Exception ex)
                {
                    throw new FileAccessException("An error occured while adding file to VS.NET project.", ex);
                }
            }

            if (applicationObject.Solution.FindProjectItem(declFile) == null)
            {
                try
                {
                    project.ProjectItems.AddFromFile(declFile);
                }
                catch (Exception ex)
                {
                    throw new FileAccessException("An error occured while adding file to VS.NET project.", ex);
                }
            }
        }

        private void AddAssembliesToProject(bool accessSOAP, bool enableValidation)
        {
            Project activeProj = GetProject();

            if ((activeProj != null))
            {
                if (!IsWebProject())
                {
                    VSProject project = activeProj.Object as VSProject;

                    project.References.Add("System.Web.Services");
                    project.References.Add("System.Xml");
                    project.References.Add("System.Data");
                    project.References.Add("System.Configuration");
                    project.References.Add("System");

                    if (accessSOAP)
                        project.References.Add("Thinktecture.Tools.Web.Services.Extensions.Messages");
                    if (enableValidation)
                        project.References.Add("Thinktecture.Tools.Web.Services.Extensions.Validation");
                }
                else
                {
                    VSWebSite webSite = activeProj.Object as VSWebSite;

                    webSite.References.AddFromGAC("System.Web.Services");
                    webSite.References.AddFromGAC("System.Xml");
                    webSite.References.AddFromGAC("System.Data");
                    webSite.References.AddFromGAC("System.Configuration");
                    webSite.References.AddFromGAC("System");

                    RegistryKey key = Registry.LocalMachine.OpenSubKey(
                        @"Software\thinktecture\WSCF\");

                    string path = (string)key.GetValue("Path");

                    if (accessSOAP)
                    {
                        if (path != null)
                        {
                            path = path + @"Shared\Thinktecture.Tools.Web.Services.Extensions.Messages.dll";
                            webSite.References.AddFromFile(path);
                        }
                    }

                    if (enableValidation)
                    {
                        if (path != null)
                        {
                            path = path + @"Shared\Thinktecture.Tools.Web.Services.Extensions.Validation.dll";
                            webSite.References.AddFromFile(path);
                        }
                    }
                }
            }
        }

        private void AddConfigFilesToProject(string configFile, bool client, bool service)
        {
            if (client)
            {
                string configFileLoc = "";

                if (configFile.EndsWith(@"\"))
                {
                    configFileLoc = configFile + @"App.config";
                }
                else
                {
                    configFileLoc = configFile + @"\App.config";
                }

                if (applicationObject.Solution.FindProjectItem(configFileLoc) == null)
                {
                    try
                    {

                        if (applicationObject.SelectedItems.Item(1).ProjectItem != null)
                            applicationObject.SelectedItems.Item(1).ProjectItem.ContainingProject.ProjectItems.AddFromFile(configFileLoc);
                        else
                            applicationObject.SelectedItems.Item(1).Project.ProjectItems.AddFromFile(configFileLoc);

                        //Project prj = GetProject();
                        //prj.ProjectItems.AddFromFile(configFileLoc);
                    }
                    catch (Exception ex)
                    {
                        throw new VSProjectException("An error occured while adding file to VS.NET project.", ex);
                    }
                }
            }

            if (service || (!service && !client))
            {
                string configFileLoc = "";

                if (configFile.EndsWith(@"\"))
                {
                    configFileLoc = configFile + @"Web.config";
                }
                else
                {
                    configFileLoc = configFile + @"\Web.config";
                }

                if (applicationObject.Solution.FindProjectItem(configFileLoc) == null)
                {
                    try
                    {
                        if (applicationObject.SelectedItems.Item(1).ProjectItem != null)
                            applicationObject.SelectedItems.Item(1).ProjectItem.ContainingProject.ProjectItems.AddFromFile(configFileLoc);
                        else
                            applicationObject.SelectedItems.Item(1).Project.ProjectItems.AddFromFile(configFileLoc);
                    }
                    catch (Exception ex)
                    {
                        throw new VSProjectException("An error occured while adding file to VS.NET project.", ex);
                    }
                }
            }
        }

        private string AddNewFileToProject(string fileName)
        {
            string fileLocation = fileName;

            // BDS: Do not attempt to add the file if it already exists.
            if (applicationObject.Solution.FindProjectItem(fileName) != null)
            {
                return fileLocation;
            }

            try
            {
                // BDS: Changed the code to copy the file to the project directory and add it to 
                // the project. (AddFromFile() is modified to AddFromFileCopy())
                //
                // BDS: Changed this back to add from an existing file.
                if (applicationObject.SelectedItems.Item(1).ProjectItem != null)
                {
                    fileLocation = applicationObject.SelectedItems.Item(1).ProjectItem.ContainingProject.ProjectItems.AddFromFile(fileName).get_FileNames(0);
                }
                else
                    fileLocation = applicationObject.SelectedItems.Item(1).Project.ProjectItems.AddFromFile(fileName).get_FileNames(0);
            }
            catch (Exception ex)
            {
                throw new VSProjectException("An error occured while adding file to VS.NET project.", ex);
            }

            return fileLocation;
        }

        /// <summary>
        /// This is used to remove a file from the current project and the local storage. 
        /// </summary>
        /// <param name="fileName">File name of the file you want to remove.</param>
        /// <remarks>
        /// It is not necessary to specify the fully qulified paths for fileName
        /// </remarks>
        private void RemoveFileFromProject(string fileName)
        {
            try
            {
                if (applicationObject.SelectedItems.Item(1).ProjectItem != null)
                {
                    applicationObject.SelectedItems.Item(1).ProjectItem.ContainingProject.ProjectItems.Item(fileName).Remove();
                }
                else
                    applicationObject.SelectedItems.Item(1).Project.ProjectItems.Item(fileName).Remove();
            }
            catch (ArgumentException)
            {
                // BDS: Gracefully ignore this as this happens 
                // if the file is not added to the project.
                Trace.WriteLine("File " + fileName + " does not exists in the project.");
            }
            catch (Exception ex)
            {
                throw new VSProjectException("An error occured while removing the file from VS.NET project.", ex);
            }
        }

        private string GetNextFileName(string fileName)
        {
            // BDS: Check for the exsisting files.
            if (!this.overwriteFiles && File.Exists(fileName))
            {
                // Try to get the next file number from the hashtable.
                int nextNumber = 1;
                if (fileCounters[fileName] != null)
                {
                    nextNumber = (int)fileCounters[fileName];
                    nextNumber++;
                    fileCounters[fileName] = nextNumber;
                }
                else
                {
                    // Add the file number along with the file name to the hashtable otherwise.
                    fileCounters.Add(fileName, nextNumber);
                }

                int lastPeriod = fileName.LastIndexOf(".");
                if (lastPeriod >= 0)
                {
                    fileName = fileName.Insert(lastPeriod, nextNumber.ToString());
                }
                else
                {
                    fileName += nextNumber.ToString();
                }
                this.addDuplictedTypesAlert = true;
            }

            return fileName;
        }

        private void DisplayWarnings(ArrayList warnings)
        {
            if (warnings.Count > 0)
            {
                string warningMessage = "";
                foreach (string warning in warnings)
                {
                    warningMessage = warningMessage + warning + "\n";
                }

                MessageBox.Show(warningMessage, "Warnings", MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
            }
        }

        // BDS 11/23/2005: Added new method called "GetProject".
        /// <summary>
        /// This method returns the reference to the currently 
        /// selected VS project.
        /// </summary>        
        private Project GetProject()
        {
            Project selectedProject = applicationObject.SelectedItems.Item(1).Project;

            if (selectedProject == null)
            {
                ProjectItem projectItem = applicationObject.SelectedItems.Item(1).ProjectItem;

                Debug.Assert((projectItem != null),
                    @"GetProject is invoked inappropriately.");

                if (projectItem != null)
                {
                    selectedProject = projectItem.ContainingProject;
                }
            }

            return selectedProject;
        }

        #endregion
    }
}